﻿//------------------------------------------------------------------------------
// Copyright © FRA & FV 2014
// All rights reserved
//------------------------------------------------------------------------------
// Binary Serialization SDK
//
// SVN revision information:
//   $Revision: 97 $
//------------------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;

namespace FRAFV.Binary.Serialization.CodeDom
{
	public static class DeclarationExpressionExtensions
	{
		#region Constants

		internal static IDictionary<string, Type> reservedTypes = new Dictionary<string, Type>{
			{ "sbyte", typeof(sbyte) },
			{ "short", typeof(short) },
			{ "int", typeof(int) },
			{ "long", typeof(long) },
			{ "byte", typeof(byte) },
			{ "ushort", typeof(ushort) },
			{ "uint", typeof(uint) },
			{ "ulong", typeof(ulong) },
			{ "bool", typeof(bool) },
			{ "float", typeof(float) },
			{ "double", typeof(double) },
			{ "string", typeof(string) },
			{ "char", typeof(char) },
			{ "sbyte[]", typeof(sbyte[]) },
			{ "short[]", typeof(short[]) },
			{ "int[]", typeof(int[]) },
			{ "long[]", typeof(long[]) },
			{ "byte[]", typeof(byte[]) },
			{ "ushort[]", typeof(ushort[]) },
			{ "uint[]", typeof(uint[]) },
			{ "ulong[]", typeof(ulong[]) },
			{ "bool[]", typeof(bool[]) },
			{ "float[]", typeof(float[]) },
			{ "double[]", typeof(double[]) },
			{ "string[]", typeof(string[]) },
			{ "char[]", typeof(char[]) },
			{ "object", typeof(object) }
		};

		#endregion

		#region Parameter declaration expressions

		public static void Add<TParam>(this CodeParameterDeclarationExpressionCollection code, string name)
		{
			code.Add(new CodeParameterDeclarationExpression(typeof(TParam), name));
		}

		#endregion

		#region Attributes declaration expressions

		public static void Add<TAttr>(this CodeAttributeDeclarationCollection code, params object[] args)
		{
			code.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(TAttr)),
				args.Select(arg => new CodeAttributeArgument(arg.AsExpression())).ToArray()));
		}

		#endregion

		#region Variable expressions

		public static CodeArgumentReferenceExpression AsArgument(this string name)
		{
			return new CodeArgumentReferenceExpression(name);
		}

		public static CodeVariableReferenceExpression AsVariable(this string name)
		{
			return new CodeVariableReferenceExpression(name);
		}

		#endregion

		#region Code expressions

		public static CodeExpression AsExpression(this object value)
		{
			var exp = value as CodeExpression;
			if (exp != null) return exp;
			return new CodePrimitiveExpression(value);
		}

		public static CodeSnippetExpression AsSnippet(this string code)
		{
			return new CodeSnippetExpression(code);
		}

		public static CodeTypeReference AsType(this string type)
		{
			Type t;
			if (reservedTypes.TryGetValue(type, out t))
				return new CodeTypeReference(t);
			return new CodeTypeReference(type);
		}

		public static CodeIndexerExpression AsIndex(this string field, string index)
		{
			return new CodeIndexerExpression(field.AsField(), index.AsVariable());
		}

		#endregion

		#region Invoke expressions

		public static CodeMethodInvokeExpression MethodInvoke(this Type type, string method, params object[] args)
		{
			return new CodeTypeReferenceExpression(type).MethodInvoke(method, args);
		}

		public static CodeMethodInvokeExpression MethodInvoke(this CodeTypeReference type, string method, params object[] args)
		{
			return new CodeTypeReferenceExpression(type).MethodInvoke(method, args);
		}

		public static CodeExpression CreateInvoke(this Type type, params object[] args)
		{
			return new CodeObjectCreateExpression(type,
				args.Select(arg => arg.AsExpression()).ToArray());
		}

		public static CodeExpression CreateInvoke(this CodeTypeReference type, params object[] args)
		{
			return new CodeObjectCreateExpression(type,
				args.Select(arg => arg.AsExpression()).ToArray());
		}

		public static CodeExpression CreateArray(this Type item, object size)
		{
			return new CodeArrayCreateExpression(item, size.AsExpression());
		}

		public static CodeExpression CreateArray(this CodeTypeReference item, object size)
		{
			return new CodeArrayCreateExpression(item, size.AsExpression());
		}

		#endregion

		#region Property expressions

		public static CodePropertyReferenceExpression Property(this Type type, string property)
		{
			return new CodeTypeReferenceExpression(type).Property(property);
		}

		public static CodePropertyReferenceExpression Property(this CodeTypeReference type, string property)
		{
			return new CodeTypeReferenceExpression(type).Property(property);
		}

		#endregion
	}

	public static class Base
	{
		#region Method invoke expressions

		public static CodeMethodInvokeExpression MethodInvoke(string method, params object[] args)
		{
			return new CodeBaseReferenceExpression().MethodInvoke(method, args);
		}

		#endregion

		#region Property expressions

		public static CodePropertyReferenceExpression Property(string property)
		{
			return new CodeBaseReferenceExpression().Property(property);
		}

		#endregion
	}
}
